// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD file. See the AUTHORS file for names of contributors.

// SPDX-License-Identifier: Apache-2.0
// Copyright 2020, Intel Corporation

// A Status encapsulates the result of an operation.  It may indicate success,
// or it may indicate an error with an associated error message.
//
// Multiple threads can invoke const methods on a Status without
// external synchronization, but if any of the threads may call a
// non-const method, all threads accessing the same Status must use
// external synchronization.

#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_
#define STORAGE_LEVELDB_INCLUDE_STATUS_H_

#include "leveldb/slice.h"
#include <string>

namespace leveldb
{

class Status {
public:
	// Create a success status.
	Status() : state_(NULL)
	{
	}
	~Status()
	{
		delete[] state_;
	}

	// Copy the specified status.
	Status(const Status &s);
	void operator=(const Status &s);

	// Return a success status.
	static Status OK()
	{
		return Status();
	}

	// Return error status of an appropriate type.
	static Status NotFound(const Slice &msg, const Slice &msg2 = Slice())
	{
		return Status(kNotFound, msg, msg2);
	}
	static Status Corruption(const Slice &msg, const Slice &msg2 = Slice())
	{
		return Status(kCorruption, msg, msg2);
	}
	static Status NotSupported(const Slice &msg, const Slice &msg2 = Slice())
	{
		return Status(kNotSupported, msg, msg2);
	}
	static Status InvalidArgument(const Slice &msg, const Slice &msg2 = Slice())
	{
		return Status(kInvalidArgument, msg, msg2);
	}
	static Status IOError(const Slice &msg, const Slice &msg2 = Slice())
	{
		return Status(kIOError, msg, msg2);
	}

	// Returns true iff the status indicates success.
	bool ok() const
	{
		return (state_ == NULL);
	}

	// Returns true iff the status indicates a NotFound error.
	bool IsNotFound() const
	{
		return code() == kNotFound;
	}

	// Returns true iff the status indicates a Corruption error.
	bool IsCorruption() const
	{
		return code() == kCorruption;
	}

	// Returns true iff the status indicates an IOError.
	bool IsIOError() const
	{
		return code() == kIOError;
	}

	// Returns true iff the status indicates a NotSupportedError.
	bool IsNotSupportedError() const
	{
		return code() == kNotSupported;
	}

	// Returns true iff the status indicates an InvalidArgument.
	bool IsInvalidArgument() const
	{
		return code() == kInvalidArgument;
	}

	// Return a string representation of this status suitable for printing.
	// Returns the string "OK" for success.
	std::string ToString() const;

private:
	// OK status has a NULL state_.  Otherwise, state_ is a new[] array
	// of the following form:
	//    state_[0..3] == length of message
	//    state_[4]    == code
	//    state_[5..]  == message
	const char *state_;

	enum Code {
		kOk = 0,
		kNotFound = 1,
		kCorruption = 2,
		kNotSupported = 3,
		kInvalidArgument = 4,
		kIOError = 5
	};

	Code code() const
	{
		return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]);
	}

	Status(Code code, const Slice &msg, const Slice &msg2);
	static const char *CopyState(const char *s);
};

inline Status::Status(const Status &s)
{
	state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
}
inline void Status::operator=(const Status &s)
{
	// The following condition catches both aliasing (when this == &s),
	// and the common case where both s and *this are ok.
	if (state_ != s.state_) {
		delete[] state_;
		state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
	}
}

} // namespace leveldb

#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_
